package ink.xiaobaibai.serviceOxy.pay.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import ink.xiaobaibai.common.WxCommon;
import ink.xiaobaibai.common.WxReturnObj;
import ink.xiaobaibai.serviceOxy.pay.IPayHttpService;
import ink.xiaobaibai.serviceOxy.pay.IPayService;
import ink.xiaobaibai.util.WxPayKeyInfo;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.UUID;

/**
 * @description:
 * @author: 小白白
 * @create: 2021-06-06
 **/

@Service
public class PayHttpServiceImpl implements IPayHttpService {

    @Autowired
    private IPayService payService;

    //预下单
    private static final String PREPARE_ORDER_URL = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";

    //查询订单
    private static final String INQUIRY_ORDER = "https://api.mch.weixin.qq.com/v3/pay/transactions/out-trade-no/%s?mchid=%s";

    //订单退款
    public static final String REFUND_AMOUNT = "https://api.mch.weixin.qq.com/v3/refund/domestic/refunds";

    private static CloseableHttpClient httpClient = HttpClientBuilder.create().build();

    /**
     * 预下单请求
     * 返回预下单id
     */
    @Override
    public String prepareOrder(PayServiceImpl.WxPayPrefixOrder wxPayPrefixOrder) {
        HttpPost httpPost = new HttpPost(PREPARE_ORDER_URL);
        String body = JSON.toJSONString(wxPayPrefixOrder);
        StringEntity entity = new StringEntity(body, "UTF-8");
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setHeader("Accept", "*/*");
        httpPost.setHeader("Authorization", getAuthorization(body, "POST", "/v3/pay/transactions/jsapi"));
        httpPost.setConfig(getRequestConfig());
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
            HttpEntity responseEntity = response.getEntity();
            JSONObject jsonObject = JSONObject.parseObject(EntityUtils.toString(responseEntity));
            return jsonObject.getString("prepay_id");
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("获取预下单id请求错误");
        } finally {
            try {
                // 释放资源
                if (response != null) {
                    response.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 查询订单状态是否已经支付
     */
    @Override
    public boolean queryOrderHavePaid(String orderId) {
        String url = String.format(INQUIRY_ORDER, orderId, WxCommon.MCHID);
        HttpGet httpGet = new HttpGet(url);
        httpGet.setHeader("Content-Type", "application/json");
        httpGet.setHeader("Accept", "*/*");
        String substring = url.substring(29);
        httpGet.setHeader("Authorization", getAuthorization(null, "GET", substring));
        httpGet.setConfig(getRequestConfig());
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
            HttpEntity responseEntity = response.getEntity();
            String str = EntityUtils.toString(responseEntity);
            PayServiceImpl.CallbackResult callbackResult = this.payService.decryptPayResponseObj(str);
            return StringUtils.equals(callbackResult.getTradeState(), "SUCCESS");
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        } finally {
            try {
                // 释放资源
                if (response != null) {
                    response.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public void returnAmount(String orderId, BigDecimal amount, String returnId, BigDecimal originalAmount, String reason) {
        HttpPost httpPost = new HttpPost(REFUND_AMOUNT);
        WxReturnObj wxReturnObj = new WxReturnObj(orderId, returnId, amount, originalAmount, reason);
        if (reason.equals(PayServiceImpl.reasonNoNotifyUrl)) {
            //无需回调
            wxReturnObj.setNotify_url(null);
        }
        String body = JSON.toJSONString(wxReturnObj);
        StringEntity entity = new StringEntity(body, "UTF-8");
        httpPost.setEntity(entity);
        httpPost.setHeader("Content-Type", "application/json");
        httpPost.setHeader("Accept", "*/*");
        httpPost.setHeader("Authorization", getAuthorization(body, "POST", "/v3/refund/domestic/refunds"));
        httpPost.setConfig(getRequestConfig());
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpPost);
            //走回调
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException("获取预下单id请求错误");
        } finally {
            try {
                // 释放资源
                if (response != null) {
                    response.close();
                }

            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取请求签名
     * 请求方法为GET时，报文主体为空。
     */
    private static String getAuthorization(String body, String methodType, String uri) {
        String uuid = UUID.randomUUID().toString().substring(0, 32);
        long timestamp = System.currentTimeMillis() / 1000;
        String key = WxPayKeyInfo.sign(methodType, uri, timestamp, uuid, body, WxPayKeyInfo.getPKCS12());
        return "WECHATPAY2-SHA256-RSA2048 " + WxPayKeyInfo.getPayHeard(WxCommon.MCHID, uuid, timestamp, WxCommon.SERIALNUMBER, key);
    }

    public static RequestConfig getRequestConfig() {
        // 配置信息
        return RequestConfig.custom()
                // 设置连接超时时间(单位毫秒)
                .setConnectTimeout(5000)
                // 设置请求超时时间(单位毫秒)
                .setConnectionRequestTimeout(5000)
                // socket读写超时时间(单位毫秒)
                .setSocketTimeout(5000)
                // 设置是否允许重定向(默认为true)
                .setRedirectsEnabled(true).build();
    }

}
